﻿using System;
using System.Globalization;
using System.Windows.Forms;

namespace QAToolsAddin.Components {
    class TextBoxCombo : TextBox {
        private bool _isnumeric;
        private double _minvalue = double.MinValue;
        private double _maxvalue = double.MaxValue;
        private double? _numberValue;
        private readonly string _decimalSeparator;
        private readonly string _groupSeparator;
        private readonly string _negativeSign;

        public string NumberFormat { get; set; }

        internal TextBoxCombo() {
            NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat;
            _decimalSeparator = numberFormatInfo.NumberDecimalSeparator;
            _groupSeparator = numberFormatInfo.NumberGroupSeparator;
            _negativeSign = numberFormatInfo.NegativeSign;
            NumberFormat = null;
        }

        public bool IsNumeric {
            get { return _isnumeric; }
            set {
                _isnumeric = value;
                if (_isnumeric)
                    Value = 0;
            }
        }

        public double MinNumber {
            get { return _minvalue; }
            set {
                _minvalue = value;
                if (_isnumeric)
                    Value = Math.Max(value, _numberValue ?? 0);
            }
        }

        public double MaxNumber {
            get { return _maxvalue; }
            set {
                _maxvalue = value;
                if (_isnumeric)
                    Value = Math.Min(value, _numberValue ?? 0);
            }
        }

        public double? Value {
            get {
                if (_isnumeric == false)
                    throw new Exception("Text box is not numeric");
                if (string.IsNullOrEmpty(base.Text))
                    return null;
                return double.Parse(base.Text);
            }
            set {
                _numberValue = value;
                if (value == null)
                    base.Text = string.Empty;
                else
                    base.Text = ((double)_numberValue).ToString(NumberFormat);
            }
        }

        public override string Text {
            get {
                return base.Text;
            }
            set {
                if (_isnumeric) {
                    try {
                        if (string.IsNullOrEmpty(value)) {
                            _numberValue = null;
                            base.Text = string.Empty;
                        } else {
                            _numberValue = double.Parse(value);
                            base.Text = ((double)_numberValue).ToString(NumberFormat);
                        }
                    } catch {
                        throw new ArgumentException("Failed to get the number from text");
                    }
                } else {
                    base.Text = value;
                }
            }
        }

        protected override void OnKeyDown(KeyEventArgs e) {
            if (_isnumeric) {
                if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up) {
                    if (string.IsNullOrEmpty(base.Text))
                        Value = 0;
                    e.Handled = true;
                    double newval = double.Parse(base.Text) + (e.KeyCode == Keys.Up ? 1 : -1);
                    Value = Math.Min(Math.Max(newval, _minvalue), _maxvalue);
                    SelectionStart = base.Text.Length + 1;
                } else if (e.KeyCode == Keys.Return) {
                    Value = Value;
                } else if (e.KeyCode == Keys.Escape) {
                    Value = _numberValue;
                }
            } else if (e.KeyCode == Keys.A && e.Control) {
                SelectAll();
            }
            base.OnKeyDown(e);
        }

        protected override void OnKeyPress(KeyPressEventArgs e) {
            base.OnKeyPress(e);
            if (_isnumeric) {
                string keyInput = e.KeyChar.ToString();
                bool ctrlKeyPressed = (ModifierKeys & Keys.Control) == Keys.Control;
                if (ctrlKeyPressed || Char.IsDigit(e.KeyChar)
                        || (keyInput.Equals(_negativeSign) && base.Text.IndexOf(_negativeSign) == -1)
                        || (keyInput.Equals(_decimalSeparator) && base.Text.IndexOf(_decimalSeparator) == -1)
                        || keyInput.Equals(_groupSeparator)
                        || e.KeyChar == '\b'
                    ) {
                } else {
                    e.Handled = true;
                }
            }
        }

    }
}
